View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.booter.Command;
23  import org.apache.maven.surefire.booter.CommandListener;
24  import org.apache.maven.surefire.booter.CommandReader;
25  import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
26  import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
27  import org.apache.maven.surefire.common.junit4.Notifier;
28  import org.apache.maven.surefire.common.junit48.FilterFactory;
29  import org.apache.maven.surefire.common.junit48.JUnit48Reflector;
30  import org.apache.maven.surefire.common.junit48.JUnit48TestChecker;
31  import org.apache.maven.surefire.providerapi.AbstractProvider;
32  import org.apache.maven.surefire.providerapi.ProviderParameters;
33  import org.apache.maven.surefire.report.ConsoleStream;
34  import org.apache.maven.surefire.report.ReporterFactory;
35  import org.apache.maven.surefire.suite.RunResult;
36  import org.apache.maven.surefire.testset.TestListResolver;
37  import org.apache.maven.surefire.testset.TestSetFailedException;
38  import org.apache.maven.surefire.util.RunOrderCalculator;
39  import org.apache.maven.surefire.util.ScanResult;
40  import org.apache.maven.surefire.util.ScannerFilter;
41  import org.apache.maven.surefire.util.TestsToRun;
42  import org.junit.runner.manipulation.Filter;
43  import org.junit.runner.notification.Failure;
44  
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  import java.util.concurrent.ConcurrentHashMap;
49  
50  import static org.apache.maven.surefire.booter.CommandReader.getReader;
51  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
52  import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
53  import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
54  import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
55  import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
56  import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
57  import static org.apache.maven.surefire.util.TestsToRun.fromClass;
58  
59  /**
60   * @author Kristian Rosenvold
61   */
62  @SuppressWarnings( { "UnusedDeclaration" } )
63  public class JUnitCoreProvider
64      extends AbstractProvider
65  {
66      private final ClassLoader testClassLoader;
67  
68      private final JUnitCoreParameters jUnitCoreParameters;
69  
70      private final ScannerFilter scannerFilter;
71  
72      private final String customRunListeners;
73  
74      private final ProviderParameters providerParameters;
75  
76      private final ScanResult scanResult;
77  
78      private final int rerunFailingTestsCount;
79  
80      private final JUnit48Reflector jUnit48Reflector;
81  
82      private final RunOrderCalculator runOrderCalculator;
83  
84      private final TestListResolver testResolver;
85  
86      private final CommandReader commandsReader;
87  
88      private TestsToRun testsToRun;
89  
90      public JUnitCoreProvider( ProviderParameters bootParams )
91      {
92          // don't start a thread in CommandReader while we are in in-plugin process
93          commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
94          providerParameters = bootParams;
95          testClassLoader = bootParams.getTestClassLoader();
96          scanResult = bootParams.getScanResult();
97          runOrderCalculator = bootParams.getRunOrderCalculator();
98          jUnitCoreParameters = new JUnitCoreParameters( bootParams.getProviderProperties() );
99          scannerFilter = new JUnit48TestChecker( testClassLoader );
100         testResolver = bootParams.getTestRequest().getTestListResolver();
101         rerunFailingTestsCount = bootParams.getTestRequest().getRerunFailingTestsCount();
102         customRunListeners = bootParams.getProviderProperties().get( "listener" );
103         jUnit48Reflector = new JUnit48Reflector( testClassLoader );
104     }
105 
106     public Iterable<Class<?>> getSuites()
107     {
108         testsToRun = scanClassPath();
109         return testsToRun;
110     }
111 
112     private boolean isSingleThreaded()
113     {
114         return jUnitCoreParameters.isNoThreading();
115     }
116 
117     public RunResult invoke( Object forkTestSet )
118         throws TestSetFailedException
119     {
120         final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
121 
122         final ConsoleStream consoleStream = providerParameters.getConsoleLogger();
123 
124         Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null;
125 
126         Notifier notifier =
127             new Notifier( createRunListener( reporterFactory, consoleStream ), getSkipAfterFailureCount() );
128         // startCapture() called in createRunListener() in prior to setTestsToRun()
129 
130         if ( testsToRun == null )
131         {
132             setTestsToRun( forkTestSet );
133         }
134 
135         // Add test failure listener
136         JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
137         notifier.addListener( testFailureListener );
138 
139         if ( isFailFast() && commandsReader != null )
140         {
141             registerPleaseStopJUnitListener( notifier );
142         }
143 
144         final RunResult runResult;
145 
146         try
147         {
148             JUnitCoreWrapper core = new JUnitCoreWrapper( notifier, jUnitCoreParameters, consoleStream );
149 
150             if ( commandsReader != null )
151             {
152                 registerShutdownListener( testsToRun );
153                 commandsReader.awaitStarted();
154             }
155 
156             notifier.asFailFast( isFailFast() );
157             core.execute( testsToRun, createCustomListeners( customRunListeners ), filter );
158             notifier.asFailFast( false );
159 
160             // Rerun failing tests if rerunFailingTestsCount is larger than 0
161             if ( isRerunFailingTests() )
162             {
163                 Notifier rerunNotifier = pureNotifier();
164                 notifier.copyListenersTo( rerunNotifier );
165                 JUnitCoreWrapper rerunCore = new JUnitCoreWrapper( rerunNotifier, jUnitCoreParameters, consoleStream );
166                 for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ )
167                 {
168                     List<Failure> failures = testFailureListener.getAllFailures();
169                     Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader );
170                     testFailureListener.reset();
171                     FilterFactory filterFactory = new FilterFactory( testClassLoader );
172                     Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests );
173                     rerunCore.execute( testsToRun, failingMethodsFilter );
174                 }
175             }
176         }
177         finally
178         {
179             runResult = reporterFactory.close();
180             notifier.removeListeners();
181         }
182         return runResult;
183     }
184 
185     private void setTestsToRun( Object forkTestSet )
186         throws TestSetFailedException
187     {
188         if ( forkTestSet instanceof TestsToRun )
189         {
190             testsToRun = (TestsToRun) forkTestSet;
191         }
192         else if ( forkTestSet instanceof Class )
193         {
194             Class<?> theClass = (Class<?>) forkTestSet;
195             testsToRun = fromClass( theClass );
196         }
197         else
198         {
199             testsToRun = scanClassPath();
200         }
201     }
202 
203     private boolean isRerunFailingTests()
204     {
205         return rerunFailingTestsCount > 0;
206     }
207 
208     private boolean isFailFast()
209     {
210         return providerParameters.getSkipAfterFailureCount() > 0;
211     }
212 
213     private int getSkipAfterFailureCount()
214     {
215         return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;
216     }
217 
218     private void registerShutdownListener( final TestsToRun testsToRun )
219     {
220         commandsReader.addShutdownListener( new CommandListener()
221         {
222             public void update( Command command )
223             {
224                 testsToRun.markTestSetFinished();
225             }
226         } );
227     }
228 
229     private void registerPleaseStopJUnitListener( final Notifier stoppable )
230     {
231         commandsReader.addSkipNextTestsListener( new CommandListener()
232         {
233             public void update( Command command )
234             {
235                 stoppable.pleaseStop();
236             }
237         } );
238     }
239 
240     private JUnit4RunListener createRunListener( ReporterFactory reporterFactory, ConsoleStream consoleStream )
241         throws TestSetFailedException
242     {
243         if ( isSingleThreaded() )
244         {
245             NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() );
246             startCapture( rm );
247             return rm;
248         }
249         else
250         {
251             final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>();
252 
253             ConcurrentRunListener listener = createInstance( testSetMap, reporterFactory, isParallelTypes(),
254                                                              isParallelMethodsAndTypes(), consoleStream );
255             startCapture( listener );
256 
257             return new JUnitCoreRunListener( listener, testSetMap );
258         }
259     }
260 
261     private boolean isParallelMethodsAndTypes()
262     {
263         return jUnitCoreParameters.isParallelMethods() && isParallelTypes();
264     }
265 
266     private boolean isParallelTypes()
267     {
268         return jUnitCoreParameters.isParallelClasses() || jUnitCoreParameters.isParallelSuites();
269     }
270 
271     private Filter createJUnit48Filter()
272     {
273         final FilterFactory factory = new FilterFactory( testClassLoader );
274         Map<String, String> props = providerParameters.getProviderProperties();
275         Filter groupFilter = factory.canCreateGroupFilter( props ) ? factory.createGroupFilter( props ) : null;
276         TestListResolver methodFilter = optionallyWildcardFilter( testResolver );
277         boolean onlyGroups = methodFilter.isEmpty() || methodFilter.isWildcard();
278         if ( onlyGroups )
279         {
280             return groupFilter;
281         }
282         else
283         {
284             Filter jUnitMethodFilter = factory.createMethodFilter( methodFilter );
285             return groupFilter == null ? jUnitMethodFilter : factory.and( groupFilter, jUnitMethodFilter );
286         }
287     }
288 
289     private TestsToRun scanClassPath()
290     {
291         TestsToRun scanned = scanResult.applyFilter( scannerFilter, testClassLoader );
292         return runOrderCalculator.orderTestClasses( scanned );
293     }
294 }